package org.openkoala.koala.popup.javaclass.crud;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.openkoala.koala.dd.ui.DataDictionaryDialog;
import org.openkoala.koala.dd.util.StaticDropUtil;
import org.openkoala.koala.deploy.curd.module.core.EntityModel;
import org.openkoala.koala.deploy.curd.module.core.FieldModel;
import org.openkoala.koala.deploy.curd.module.core.model.RelationFieldModel;
import org.openkoala.koala.deploy.curd.module.pojo.ValidateRule;
import org.openkoala.koala.deploy.curd.module.ui.Model;
import org.openkoala.koala.deploy.curd.module.ui.UIWidget;
import org.openkoala.koala.deploy.curd.module.ui.view.RelativeReadOnlyView;
import org.openkoala.koala.deploy.curd.module.ui.view.StaticDropView;

public class EditFieldConfigurationDialog extends Dialog {

	private CrudComponent parent;
	
	private List<FieldModel> fieldModels;
	private List<FieldModel> associationFieldModels;
	private UIWidget widget;
	private Map<String, Map<String, String>> dropDatasMap;
	
	private Model model;
	private String modelType;
	
	private Composite mainComposite;
	private Combo fieldsCombo;
	private Text viewText;
	private Combo editTypesCombo;
	
	private Composite expressComposite;
	private Combo expressCombo;

	private Composite dropMapComposite;
	private Combo dropMapCombo;
	
	private Composite editFiledValidateComposite;
	private Combo validateTypeCombo;
	private Button isRequired;
	private Text regExpText;
	private Label regExpLabel;
	
	private GridData textGridData = new GridData(GridData.FILL_HORIZONTAL);
	
	private EditFieldConfigurationDialog(Shell shell, CrudComponent parent, UIWidget widget, List<FieldModel> fieldModels, 
			List<FieldModel> associationFieldModels, Model model) {
		super(shell);
		this.parent = parent;
		this.widget = widget;
		this.fieldModels = fieldModels;
		this.associationFieldModels = associationFieldModels;
		this.model = model;
		this.modelType = CrudUtils.getModelType(model);
		
		if (CrudConstants.MODEL_EDIT.equals(modelType)) {
			refreshDropDatasMap();
		}
	}

	private void refreshDropDatasMap() {
		StaticDropUtil staticDropUtil = new StaticDropUtil();
		dropDatasMap = staticDropUtil.getStaticDatas();
		
		if (dropMapCombo != null) {
			String selectionKey = dropMapCombo.getText();
			dropMapCombo.removeAll();
			for (String dropDictionary : dropDatasMap.keySet()) {
				dropMapCombo.add(dropDictionary);
			}
			dropMapCombo.setText(selectionKey);
		}
	}
	
	public static EditFieldConfigurationDialog createByAddField(Shell shell, CrudComponent parent, 
			List<FieldModel> fieldModels, Model model) {
		return new EditFieldConfigurationDialog(shell, parent, null, fieldModels, null, model);
	}

	public static EditFieldConfigurationDialog createByUpdateField(Shell shell, CrudComponent parent, UIWidget widget, Model model) {
		return new EditFieldConfigurationDialog(shell, parent, widget, null, null, model);
	}

	public static EditFieldConfigurationDialog createByUpdateAssociationField(Shell shell, CrudComponent parent, UIWidget widget, 
			Model model, List<FieldModel> associationFieldModels) {
		return new EditFieldConfigurationDialog(shell, parent, widget, null, associationFieldModels, model);
	}
	
	@Override
	protected void configureShell(Shell newShell) {
		super.configureShell(newShell);
		newShell.setText("Edit Configuration");
	}
	
	@Override
	protected Control createDialogArea(Composite parent) {
		mainComposite = new Composite(parent, SWT.NONE);
		initializeDialogUnits(mainComposite);

		GridData mainGridData = new GridData(250, 210);
		mainComposite.setLayoutData(mainGridData);

		GridLayout gridLayout = new GridLayout();
		gridLayout.numColumns = 1;
		mainComposite.setLayout(gridLayout);

		generateConfigComposite(mainComposite);

		return parent;
	}
	
	private void generateConfigComposite(Composite parentComposite) {
		GridData gridData = new GridData(GridData.FILL_BOTH);
		GridLayout gridLayout = new GridLayout(2, false);
		
		Composite composite = new Composite(parentComposite, SWT.NONE);
		composite.setLayout(gridLayout);
		composite.setLayoutData(gridData);

		if (fieldModels != null) {
			Label fieldLable = new Label(composite, SWT.NONE);
			fieldLable.setText("属性");
			fieldsCombo = new Combo(composite, SWT.READ_ONLY);
			for (FieldModel fieldModel : fieldModels) {
				fieldsCombo.add(fieldModel.getName());
			}
			fieldsCombo.addSelectionListener(new FieldsComboSelectionListener());
		}
		
		Label viewLabel = new Label(composite, SWT.NONE);
		viewLabel.setText("显示名称");
		
		viewText = new Text(composite, SWT.BORDER);
		viewText.setLayoutData(textGridData);
		if (widget != null) {
			viewText.setText(widget.getName());
		}
		
		if (CrudConstants.MODEL_EDIT.equals(modelType)) {
			Label editTypesLabel = new Label(composite, SWT.NONE);
			editTypesLabel.setText("编辑框类型");
			editTypesCombo = new Combo(composite, SWT.READ_ONLY);
			for (EditType editType : EditType.values()) {
				if (editType == EditType.ENTITY_COMBO_BOX) continue; //TODO 暂时不支持实体下拉框.
				editTypesCombo.add(editType.getDescription());
			}
			editTypesCombo.addSelectionListener(new EditTypesComboSelectionListener());
			if (widget != null) {
				editTypesCombo.setText(CrudUtils.getEditTypeNameByUIWiget(widget));
			}
			
			
			isRequired = new Button(composite, SWT.CHECK);
			isRequired.setText("是否必填");
			if (widget != null) {
				isRequired.setSelection(widget.isRequired());
			}
			Label emptyLabel = new Label(composite, SWT.NONE);
		}
		
		if (widget != null && widget instanceof RelativeReadOnlyView) {
			createExpressCombo(widget.getExpress(), mainComposite);
		}
		
		if (editTypesCombo != null && widget != null && EditType.COMBO_BOX == EditType.getByDescription(editTypesCombo.getText())) {
			createDropMapCombo(getKeyByDropData(((StaticDropView) widget).getValueMap()), mainComposite);
		}
		
		if (editTypesCombo != null && widget != null 
				&& (EditType.TEXT_FIELD == EditType.getByDescription(editTypesCombo.getText()) || EditType.TEXT_AREA == EditType.getByDescription(editTypesCombo.getText()))) {
			createValidateTypeCombo(mainComposite, widget.getValidateRule(), widget.getValidateExpress());
		}
	}
	
	private String getKeyByDropData(Map<String, String> dropData) {
		String result = "";
		for (String dropDictionary : dropDatasMap.keySet()) {
			if (dropDatasMap.get(dropDictionary).equals(dropData)) {
				return dropDictionary;
			}
		}
		
		return result;
	}
	
	private void createExpressCombo(String express, Composite parentComposite) {
		GridData gridData = new GridData(GridData.FILL_BOTH);
		GridLayout gridLayout = new GridLayout(2, false);
		
		expressComposite = new Composite(parentComposite, SWT.NONE);
		expressComposite.setLayout(gridLayout);
		expressComposite.setLayoutData(gridData);

		Label expressLabel = new Label(expressComposite, SWT.NONE);
		expressLabel.setText("关联实体显示属性");
		expressCombo = new Combo(expressComposite, SWT.READ_ONLY);
		
		if (widget == null) {
			addExpressComboItems(express);
		} else {
			addExpressComboItems();
		}
		
		expressCombo.setText(express);
	}
	
	private void createDropMapCombo (String dropDataKey, Composite parentComposite) {
		GridData gridData = new GridData(GridData.FILL_BOTH);
		GridLayout gridLayout = new GridLayout(3, false);
		
		dropMapComposite = new Composite(parentComposite, SWT.NONE);
		dropMapComposite.setLayout(gridLayout);
		dropMapComposite.setLayoutData(gridData);

		Label label = new Label(dropMapComposite, SWT.NONE);
		label.setText("选择下拉字典");
		dropMapCombo = new Combo(dropMapComposite, SWT.READ_ONLY);
		
		for (String dropDictionary : dropDatasMap.keySet()) {
			dropMapCombo.add(dropDictionary);
		}
		dropMapCombo.setText(dropDataKey);
		
		Button button = new Button(dropMapComposite, SWT.PUSH);
		button.setText("配置字典");
		button.addSelectionListener(new DataDicConfigButtonSelectionListener());
	}

	private void createValidateTypeCombo(Composite parentComposite, ValidateRule validateType, String regExp) {
		GridData gridData = new GridData(GridData.FILL_BOTH);
		GridLayout gridLayout = new GridLayout(2, false);

		editFiledValidateComposite = new Composite(parentComposite, SWT.NONE);
		editFiledValidateComposite.setLayout(gridLayout);
		editFiledValidateComposite.setLayoutData(gridData);
		
		Label label = new Label(editFiledValidateComposite, SWT.NONE);
		label.setText("选择校验类型");
		validateTypeCombo = new Combo(editFiledValidateComposite, SWT.READ_ONLY);
		validateTypeCombo.addSelectionListener(new ValidateTypeComboSelectionListener());
		
		for (ValidateRule theValidateType : ValidateRule.values()) {
			validateTypeCombo.add(theValidateType.getRuleName());
		}
		if (validateType != null) {
			validateTypeCombo.setText(validateType.getRuleName());
		}
		
		if (validateType == ValidateRule.Regex) {
			createRegExpText(regExp);
		}
	}
	
	private void createRegExpText(String regExp) {
		regExpLabel = new Label(editFiledValidateComposite, SWT.NONE);
		regExpLabel.setText("正则表达式");
		
		regExpText = new Text(editFiledValidateComposite, SWT.BORDER);
		regExpText.setLayoutData(textGridData);
		regExpText.setText(regExp);
	}
	
	private void addExpressComboItems() {
		for (FieldModel fieldModel : associationFieldModels) {
			expressCombo.add(fieldModel.getName());
		}
	}
	
	private void changeExpressComboData(String express) {
		expressCombo.removeAll();
		addExpressComboItems(express);
	}

	private void addExpressComboItems(String express) {
		RelationFieldModel relationFieldModel = (RelationFieldModel) CrudUtils.getFieldModelByName(express, fieldModels);
		EntityModel entityModel = relationFieldModel.getRelationModel().getEntityModel();
		associationFieldModels = new ArrayList<FieldModel>(entityModel.getFields());
		associationFieldModels.remove(entityModel.getObjectValueFieldModel());
		associationFieldModels.remove(entityModel.getRelationFieldModel());
		for (FieldModel fieldModel : associationFieldModels) {
			expressCombo.add(fieldModel.getName());
		}
	}
	
	@Override
	protected void okPressed() {
		if (!validate()) {
			return;
		}
		
		String express = null;
		if (expressCombo != null) {
			express = expressCombo.getText();
		}
		
		Map<String, String> dropData = null;
		if (dropMapCombo != null) {
			dropData = dropDatasMap.get(dropMapCombo.getText());
		}
		
		if (widget == null) {
			addField(express, dropData);
		} else {
			updateField(express, dropData);
		}
		super.okPressed();
	}

	private void addField(String express, Map<String, String> dropData) {
		String fieldName = fieldsCombo.getText();
		
		UIWidget theWidget = null;
    	if (modelType.equals(CrudConstants.MODEL_EDIT)) {
    		theWidget = CrudUtils.createEditUIWidgetBy(fieldName, viewText.getText().trim(), express, 
    				CrudUtils.getFieldModelByName(fieldName, fieldModels).getType(), EditType.getByDescription(editTypesCombo.getText()), dropData);
    		setValidate(theWidget);
    	} else if (associationFieldModels != null) {
    		theWidget = CrudUtils.createRelativeReadOnlyView(fieldName, viewText.getText().trim(), express, 
    				CrudUtils.getFieldModelByName(express, associationFieldModels).getType());
    	} else {
    		theWidget = CrudUtils.createReadOnlyView(fieldName, viewText.getText().trim(), express, 
    				CrudUtils.getFieldModelByName(fieldName, fieldModels).getType());
    	}
    	
		model.getViews().add(theWidget);
		parent.addItem(theWidget);
	}

	private void updateField(String express, Map<String, String> dropData) {
		if (express == null) {
			express = widget.getExpress();
		}
		
    	if (modelType.equals(CrudConstants.MODEL_EDIT)) {
    		UIWidget newWidget = CrudUtils.createEditUIWidgetBy(widget.getExpress(), viewText.getText(), 
    				express, widget.getType(), EditType.getByDescription(editTypesCombo.getText()), dropData);
        	if (hasChangedEditType(widget, newWidget)) {
        		updateModelViews(widget, newWidget);
            	parent.update(widget, newWidget);
            	return;
        	}
    	}
    	
    	widget.setName(viewText.getText());
		if (express != null) {
			widget.setExpress(express);
			if (widget instanceof RelativeReadOnlyView) {
				widget.setType(CrudUtils.getFieldModelByName(express, associationFieldModels).getType());
			}
		}
		if (dropData != null) {
			((StaticDropView) widget).setValueMap(dropData);
		}
		
		setValidate(widget);
		parent.refresh(widget);
	}

	private void setValidate(UIWidget theWidget) {
		if (isRequired != null) {
			theWidget.setRequired(isRequired.getSelection());
		}
		if (validateTypeCombo != null && !validateTypeCombo.getText().isEmpty()) {
			theWidget.setValidateRule(ValidateRule.string2Enum(validateTypeCombo.getText()));
			if (regExpText != null && !regExpText.getText().isEmpty()) {
				theWidget.setValidateExpress(regExpText.getText());
			}
		}
	}
	
    private boolean hasChangedEditType(UIWidget oldWidget, UIWidget newWidget) {
    	return newWidget.getClass().equals(oldWidget.getClass()) ? false : true;
    }
    
    private void updateModelViews(UIWidget oldWidget, UIWidget newWidget) {
    	model.getViews().remove(oldWidget);
    	model.getViews().add(newWidget);
    }
	
	private boolean validate() {
		if (fieldsCombo != null && fieldsCombo.getText().isEmpty()) {
			MessageDialog.openError(getShell(), "错误提示！", "请选择属性！");
			return false;
		}
		if (viewText.getText().isEmpty()) {
			MessageDialog.openError(getShell(), "错误提示！", "请填写显示名称！");
			return false;
		}
		if (expressCombo != null && expressCombo.getText().isEmpty()) {
			MessageDialog.openError(getShell(), "错误提示！", "请选择关联属性！");
			return false;
		}
		if (editTypesCombo != null && editTypesCombo.getText().isEmpty()) {
			MessageDialog.openError(getShell(), "错误提示！", "请选择编辑类型！");
			return false;
		}
		if (regExpText != null && regExpText.getText().isEmpty()) {
			MessageDialog.openError(getShell(), "错误提示！", "请填写正则表达式！");
			return false;
		}
		return true;
	}
	
	private class FieldsComboSelectionListener implements SelectionListener {
		@Override
		public void widgetSelected(SelectionEvent e) {
			FieldModel fieldModel = CrudUtils.getFieldModelByName(fieldsCombo.getText(), fieldModels);
			if (expressCombo == null && fieldModel != null && CrudUtils.isAssociationType(fieldModel.getType())) {
				createExpressCombo(fieldModel.getName(), mainComposite);
				mainComposite.layout();
			} else if (expressCombo != null && fieldModel != null && CrudUtils.isAssociationType(fieldModel.getType())) {
				changeExpressComboData(fieldModel.getName());
			} else if (expressCombo != null) {
				expressCombo = null;
				expressComposite.dispose();
			}
		}

		@Override
		public void widgetDefaultSelected(SelectionEvent e) {
		}
	}
	
	private class EditTypesComboSelectionListener implements SelectionListener {
		@Override
		public void widgetSelected(SelectionEvent e) {
			if (dropMapCombo != null && EditType.COMBO_BOX != EditType.getByDescription(editTypesCombo.getText())) {
				dropMapCombo = null;
				dropMapComposite.dispose();
			}
			
			if (validateTypeCombo != null
					&& EditType.TEXT_FIELD != EditType.getByDescription(editTypesCombo.getText()) 
					&& EditType.TEXT_AREA != EditType.getByDescription(editTypesCombo.getText())) {
				validateTypeCombo = null;
				editFiledValidateComposite.dispose();
			}
			
			if (dropMapCombo == null && EditType.COMBO_BOX == EditType.getByDescription(editTypesCombo.getText())) {
				createDropMapCombo("", mainComposite);
				mainComposite.layout();
				return;
			}
			
			if (validateTypeCombo == null 
					&& (EditType.TEXT_FIELD == EditType.getByDescription(editTypesCombo.getText()) || EditType.TEXT_AREA == EditType.getByDescription(editTypesCombo.getText()))) {
				createValidateTypeCombo(mainComposite, null, "");
				mainComposite.layout();
				return;
			}
		}

		@Override
		public void widgetDefaultSelected(SelectionEvent e) {
		}
	}
	
	private class ValidateTypeComboSelectionListener implements SelectionListener {

		@Override
		public void widgetSelected(SelectionEvent e) {
			if (regExpText != null && ValidateRule.string2Enum(validateTypeCombo.getText()) != ValidateRule.Regex) {
				regExpLabel.dispose();
				regExpLabel = null;
				regExpText.dispose();
				regExpText = null;
			} else if (regExpText == null && ValidateRule.string2Enum(validateTypeCombo.getText()) == ValidateRule.Regex) {
				createRegExpText("");
				editFiledValidateComposite.layout();				
			}
		}

		@Override
		public void widgetDefaultSelected(SelectionEvent e) {
		}
		
	}
	
	private class DataDicConfigButtonSelectionListener implements SelectionListener {
		@Override
		public void widgetSelected(SelectionEvent e) {
		      DataDictionaryDialog dialog = new DataDictionaryDialog(getShell());
		      dialog.open();
		      
		      refreshDropDatasMap();
		}

		@Override
		public void widgetDefaultSelected(SelectionEvent e) {
		}
	}
	
}
